
#include "stdafx.h"
#include "Colors.h"

void RGB2HSV(const RGBQUAD * pRGB, ST_HSV * pHSV)
{
	intptr_t mx = max(max(pRGB->rgbRed, pRGB->rgbGreen), pRGB->rgbBlue), mn = min(min(pRGB->rgbRed, pRGB->rgbGreen), pRGB->rgbBlue);
	if (mx == mn)
		pHSV->hsvH = 0;
	else if (mx == pRGB->rgbRed)
		pHSV->hsvH = (double)60 * (pRGB->rgbGreen - pRGB->rgbBlue) / (mx - mn) + (pRGB->rgbGreen >= pRGB->rgbBlue ? 0 : 360);
	else if (mx == pRGB->rgbGreen)
		pHSV->hsvH = (double)60 * (pRGB->rgbBlue - pRGB->rgbRed) / (mx - mn) + 120;
	else
		pHSV->hsvH = (double)60 * (pRGB->rgbRed - pRGB->rgbGreen) / (mx - mn) + 240;
	pHSV->set(pHSV->hsvH, mx == 0 ? 0 : ((double)(mx - mn) / mx), (double)mx / 255);
}

void HSV2RGB(const ST_HSV * pHSV, RGBQUAD * pRGB)
{
	double dr, dg, db;
	if (pHSV->hsvS <= 0)
		dr = dg = db = pHSV->hsvV;
	else
	{
		double h = pHSV->hsvH / 60; intptr_t i = (intptr_t)h;
		double f = h - i;
		double a = pHSV->hsvV*(1 - pHSV->hsvS),
			b = pHSV->hsvV*(1 - pHSV->hsvS*f),
			c = pHSV->hsvV*(1 - pHSV->hsvS*(1 - f));
		switch (i)
		{
		case 0:	dr = pHSV->hsvV; dg = c; db = a; break;
		case 1:	dr = b; dg = pHSV->hsvV; db = a; break;
		case 2:	dr = a; dg = pHSV->hsvV; db = c; break;
		case 3:	dr = a; dg = b; db = pHSV->hsvV; break;
		case 4:	dr = c; dg = a; db = pHSV->hsvV; break;
		case 5:	dr = pHSV->hsvV; dg = a; db = b; break;
		}
	}
	dr *= 255; pRGB->rgbRed = dr<0.0 ? 0 : (dr>255.0 ? 255 : (unsigned char)dr);
	dg *= 255; pRGB->rgbGreen = dg<0.0 ? 0 : (dg>255.0 ? 255 : (unsigned char)dg);
	db *= 255; pRGB->rgbBlue = db<0.0 ? 0 : (db>255.0 ? 255 : (unsigned char)db);
}

intptr_t LABl(intptr_t r, intptr_t g, intptr_t b)
{
	intptr_t y = 223002 * r + 749900 * g + 75675 * b;	//(0.212671 * r + 0.715160 * g + 0.072169 * b)/255
	if (y > 2367978)	//y>0.008856
	{
		return (intptr_t)(295.8*pow((double)y / 0xff00000, 0.33333333) - 40.8);
	}
	else
	{
		return (intptr_t)((((long long)y) * 9471703) >> 40);		//903.3*y*255/100
	}
}
void RGB2LAB(const RGBQUAD *pRGB, ST_LAB *pLAB)
{
	double x = 0.412453*pRGB->rgbRed + 0.357580*pRGB->rgbGreen + 0.180423*pRGB->rgbBlue,
		y = 0.212671*pRGB->rgbRed + 0.715160*pRGB->rgbGreen + 0.072169*pRGB->rgbBlue,
		z = 0.019334*pRGB->rgbRed + 0.119193*pRGB->rgbGreen + 0.950227*pRGB->rgbBlue;
	x = x / (255.0*0.950456);
	y = y / 255.0;
	z = z / (255.0*1.088754);
	double fx, fy, fz, l, a, b;
	if (y>0.008856)
	{
		fy = pow(y, 1.0 / 3.0);
		l = 116.0*fy - 16.0;
	}
	else
	{
		fy = 7.787*y + 16.0 / 116.0;
		l = 903.3*y;
	}
	if (x>0.008856)
	{
		fx = pow(x, 1.0 / 3.0);
	}
	else
	{
		fx = 7.787*x + 16.0 / 116.0;
	}
	if (z>0.008856)
	{
		fz = pow(z, 1.0 / 3.0);
	}
	else
	{
		fz = 7.787*z + 16.0 / 116.0;
	}
	a = 500.0*(fx - fy);
	b = 200.0*(fy - fz);
	/*
	double BLACK = 20.0;
	double YELLOW = 70.0;
	if (l< BLACK)
	{
	a *= exp((l - BLACK) / (BLACK / 4));
	b *= exp((l - BLACK) / (BLACK / 4));
	l = 20;
	}
	if (b > YELLOW) b = YELLOW;
	*/
	pLAB->l = l * 255 / 100; pLAB->a = a; pLAB->b = b;
}

void LAB2RGB(const ST_LAB *pLAB, RGBQUAD *pRGB)
{
	double l = pLAB->l * 100 / 255, a = pLAB->a, b = pLAB->b;
	double fx, fy, fz;
	double x, y, z;
	double dr, dg, db;
	fy = (l + 16.0) / 116.0;
	fy = fy*fy*fy;

	if (fy > 0.008856)
	{
		y = fy;
	}
	else
	{
		fy = l / 903.3;
	}

	if (fy > 0.008856)
	{
		fy = pow(fy, 1.0 / 3.0);
	}
	else
	{
		fy = 7.787*fy + 16.0 / 116.0;
	}

	fx = a / 500.0 + fy;
	if (fx > 0.206893)
	{
		x = pow(fx, 3.0);
	}
	else
	{
		x = (fx - 16.0 / 116.0) / 7.787;
	}

	fz = fy - b / 200.0;
	if (fz > 0.206893)
	{
		z = pow(fz, 3);
	}
	else
	{
		z = (fz - 16.0 / 116.0) / 7.787;
	}

	x = x*0.950456*255.0;
	y = y*255.0;
	z = z*1.088754*255.0;

	// [ R ]   [  3.240479 -1.537150 -0.498535 ]   [ X ]
	// [ G ] = [ -0.969256  1.875992  0.041556 ] * [ Y ]
	// [ B ]   [  0.055648 -0.204043  1.057311 ]   [ Z ]
	dr = 3.240479*x - 1.537150*y - 0.498535*z;
	dg = -0.969256*x + 1.875992*y + 0.041556*z;
	db = 0.055648*x - 0.204043*y + 1.057311*z;

	pRGB->rgbRed = dr<0.0 ? 0 : (dr>255.0 ? 255 : (unsigned char)dr);
	pRGB->rgbGreen = dg<0.0 ? 0 : (dg>255.0 ? 255 : (unsigned char)dg);
	pRGB->rgbBlue = db<0.0 ? 0 : (db>255.0 ? 255 : (unsigned char)db);
}
